﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;

namespace ExcelMerge;

public static class ListExtension
{
    public static bool ElementEquals<T>(this List<T> list, List<T> other) where T : IEquatable<T>
    {
        if (list.Count != other.Count)
        {
            return false;
        }

        for (int i = 0; i < list.Count; i++)
        {
            if (!list[i].Equals(other[i]))
            {
                return false;
            }
        }

        return true;
    }

    public static List<T> Slice<T>(this List<T> list, int start) where T : IEquatable<T>
    {
        return list.GetRange(start, list.Count - start);
    }

    public static List<T> Splice<T>(this List<T> input, int start, int count, params T[] objects)
    {
        List<T> deletedRange = input.GetRange(start, count);
        input.RemoveRange(start, count);
        input.InsertRange(start, objects);

        return deletedRange;
    }
    
    public static int IndexOf<T>(this List<T> list, List<T> other, int start = 0) where T : IEquatable<T>
    {
        if (other.Count + start > list.Count)
        {
            return -1;
        }

        var listSpan = list.AsSpan();
        var otherSpan = other.AsSpan();
        for (int i = start; i + other.Count <= list.Count; i++)
        {
            if (listSpan.Slice(i, other.Count).ElementEquals(otherSpan))
            {
                return i;
            }
        }

        return -1;
    }
    
    public static int LastIndexOf<T>(this List<T> list, List<T> other) where T : IEquatable<T>
    {
        if (other.Count > list.Count)
        {
            return -1;
        }

        var listSpan = list.AsSpan();
        var otherSpan = other.AsSpan();
        for (int i = list.Count - other.Count; i >= 0; i--)
        {
            if (listSpan.Slice(i, other.Count).ElementEquals(otherSpan))
            {
                return i;
            }
        }

        return -1;
    }

    public static bool StartsWith<T>(this List<T> list, List<T> other) where T : IEquatable<T>
    {
        if (other.Count > list.Count)
        {
            return false;
        }

        return list.IndexOf(other) == 0;
    }

    public static bool EndsWith<T>(this List<T> list, List<T> other) where T : IEquatable<T>
    {
        if (other.Count > list.Count)
        {
            return false;
        }

        return list.LastIndexOf(other) == list.Count - other.Count;
    }
    
    public static string ToElementString<T>(this List<T> list) where T : IDiffItem<T>
    {
        return string.Join("", list.Select(x => x.ToString()));
    }

    public static ReadOnlySpan<T> AsSpan<T>(this List<T> list)
    {
        return CollectionsMarshal.AsSpan(list);
    }
}